home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 19 / CU Amiga Magazine's Super CD-ROM 19 (1998)(EMAP Images)(GB)[!][issue 1998-02].iso / CUCD / Programming / LEDA / source / src / plane / _simplex.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-16  |  13.3 KB  |  563 lines

  1. /*******************************************************************************
  2. +
  3. +  LEDA  3.1c
  4. +
  5. +
  6. +  _simplex.c
  7. +
  8. +
  9. +  Copyright (c) 1994  by  Max-Planck-Institut fuer Informatik
  10. +  Im Stadtwald, 6600 Saarbruecken, FRG     
  11. +  All rights reserved.
  12. *******************************************************************************/
  13.  
  14.  
  15. /****************************************************************************
  16. *                                                                           *
  17. *    simplex.c                                                              *
  18. *    *********                                                              *
  19. *    ist ein Programm zur Loesung linearer Programme !                      *
  20. *    *************************************************                      *
  21. *                                                                           *
  22. *    Die Implementierung basiert auf dem Zweiphasen-Simplex-Verfahren       *
  23. *    aus Dinkelbach, Operations Research, Kapitel 1.                        *
  24. *                                                                           *
  25. *    Kommentare und die Wahl der Bezeichnernamen beziehen sich in der       *
  26. *    Regel auf die entsprechenden Stellen im Buch.                          *
  27. *                                                                           *
  28. *    29.06.1992                                                             *
  29. *                                                                           *
  30. *    Sascha Portz und Johannes Helders                                      *
  31. *                                                                           *
  32. ****************************************************************************/
  33.  
  34.  
  35. #include <LEDA/simplex.h>
  36.  
  37.  
  38. static void Init_Tableau (matrix A, matrix& M, vector c, vector b,int kl,int gr,
  39.            int gl, int *&B, int *&NB, int zeilen, int spalten, int n)
  40. {
  41.    int nb = n;                      // Zaehler zur Initialisierung der Menge NB
  42.  
  43.    for ( int s=0 ; s<n; s++ )
  44.       M(0,s+1) = -c[s];
  45.  
  46.    for (int z=0; z<kl; z++ )
  47.    {
  48.       for ( int s=0; s < n; s++ )
  49.      M(z+1,s+1) = A(z,s);
  50.       M(z+1,n+z+1) = 1;              // Schlupfvariablen setzen
  51.       B[z] = n+z+1;                  // der z.te Basisvektor
  52.    }
  53.  
  54.    for ( z=0; z<gr; z++ )
  55.    {
  56.       for ( int s=0; s < n; s++ )
  57.      M(kl+z+1,s+1) = A(kl+z,s);
  58.       M(z+kl+1,n+z+kl+1) = -1;        // bei >= Nebenbedingungen neg. Schlupf
  59.       M(z+kl+1,n+kl+gr+z+1) = 1;      // kuenstliche Variable
  60.       B[kl+z] = n+kl+gr+z+1;          // der kl+gr+z.te Basisvektor
  61.       NB[nb] = n+kl+z+1; nb++;        // n+kl+gr+z ist Nichtbasisvaiable
  62.       M(zeilen-1,n+kl+gr+z+1) = 1;    // Initialisieren der Hilfszielfunktion
  63.    }
  64.  
  65.    for ( z=0; z<gl; z++ )
  66.    {
  67.       for ( int s=0; s<n; s++ )
  68.      M(z+kl+gr+1,s+1) = A(z+kl+gr,s);
  69.       M(z+kl+gr+1,n+kl+2*gr+z+1) = 1;  // kuenstliche Variable
  70.       B[kl+gr+z] = kl+2*gr+n+z+1;      // der z.te Basisvektor
  71.       M(zeilen-1,n+kl+2*gr+z+1) = 1;   //Initialisieren der Hilfszielfunktion
  72.    }
  73.  
  74.    for ( z=0; z<b.dim(); z++)
  75.       M(z+1,0) = b[z];
  76.  
  77.    for( s=0; s < n ; s++)               // 1,...,n sind Nichtbasisvariablen
  78.       NB[s] = s+1;
  79.  
  80.    for ( z=kl+1; z<=kl+gr+gl; z++)      // Subtrahieren der Zeilen mit kuenstl.
  81.       for ( s=0; s<spalten; s++)       // Variablen von der letzten Zeile
  82.      M(zeilen-1,s) = M(zeilen-1,s) - M(z,s);
  83.  
  84. }
  85.  
  86.  
  87. static void InitIntArray (int *&A, int *B, int l)
  88.  
  89. // Initialisiert das int-Array A der Laenge l mit dem int-Array B
  90.  
  91. {
  92.    for (int i=0; i<l; i++)
  93.       A[i] = B[i];
  94. }
  95.  
  96.  
  97. static void InitMatrix (matrix &A, matrix B, int dim1, int dim2)
  98.  
  99. // Initialisierung der Matrix A mit der Matrix B
  100.  
  101. {
  102.    for (int l=0; l<dim1; l++)
  103.       for (int m=0; m<dim2; m++)
  104.      A(l,m) = B(l,m);
  105. }
  106.  
  107.  
  108. static int PivotSpalte (matrix M, int *&NB, int z, int l, int m)
  109.  
  110. // in der Zeile z (z=0 oder z = m+1) wird die Pivotspalte gesucht
  111.  
  112. // l ist die Groesse der Menge der Nichtbasisvariablen
  113.  
  114. // accept = 1 impliziert die Gueltigkeit der gefundenen Pivotspalte, d.h.
  115. // es gibt in dieser Zeile ein Element, das > 0 ist,
  116. // ist dies nicht der Fall so wird nach einer neuen Pivotspalte gesucht
  117. // iter zaehlt die Anzahl der Iterationen
  118.  
  119. {
  120.    double eps = 0.00001;    // das Intervall [-eps..eps] entspricht NULL
  121.  
  122.    double min=-eps;
  123.    double minmin=-10000;
  124.    int mins = 0;
  125.    int p, accept = 0;
  126.    int iter = 1;
  127.  
  128.    while ( (accept == 0) && (iter <= l) )
  129.    {
  130.       for (int q=0; q<l; q++)
  131.      if ( ( M(z,NB[q]) <= min ) && ( M(z,NB[q]) > minmin ) )
  132.      {
  133.         min = M(z,NB[q]);
  134.         mins = NB[q];
  135.      }
  136.  
  137.       p = 1;                                // Test ob die gefundene Spalte
  138.       while ( (p <= m) && (accept == 0) )   // als Pivotspalte akzeptiert
  139.       {                                     // wird
  140.      if ( M(p,mins) > eps )
  141.         accept = 1;
  142.      p++;
  143.       }
  144.  
  145.       if (accept == 0)                      // falls nicht
  146.       {                                     // -> Suche nach der naechst-
  147.      minmin = min;                     // besten Pivotspalte
  148.      min = -eps;
  149.      q = 0;
  150.      mins = 0;
  151.       }
  152.       iter++;
  153.    }
  154.  
  155.    return mins;
  156. }
  157.  
  158.  
  159. static int D_PivotSpalte (matrix M, int *&NB, int z,int n,int kl,int gr)
  160.  
  161. // Liefert die Pivotspalte fuer einen Dualsimplexschritt in der Zeile z
  162.  
  163. {
  164.    double eps = 0.00001;    // das Intervall [-eps..eps] entspricht NULL
  165.  
  166.    double min = 1000;
  167.    int mins = 0;
  168.  
  169.    for(int q=0; q<n+gr; q++)
  170.       if ( ( M(z,NB[q]) < -eps ) && ( NB[q] <= n+kl+gr ) )
  171.      if ( min >= -M(0,NB[q]) / M(z,NB[q]) )
  172.      {
  173.         min = -M(0,NB[q]) / M(z,NB[q]);
  174.         mins = NB[q];
  175.      }
  176.    return mins;
  177. }
  178.  
  179.  
  180. static int PivotZeile (matrix M, int s, int m)
  181.  
  182. // Liefert die Pivotzeile fuer einen Primalsimplexschritt in der Spalte s
  183.  
  184. {
  185.    double eps = 0.00001;    // das Intervall [-eps..eps] entspricht NULL
  186.  
  187.    int minz = 0;
  188.    double min = 1000;
  189.  
  190.    for (int p=1; p<=m; p++)
  191.       if ( M(p,s) > eps )
  192.       if (min > M(p,0)/M(p,s) )
  193.       {
  194.          min = M(p,0)/M(p,s);
  195.          minz = p;
  196.       }
  197.    return minz;
  198. }
  199.  
  200.  
  201. static void Basiswechsel (matrix &M, int p, int q, int n,int kl, int gr, int gl)
  202.  
  203. // Basiswechsel : siehe Dinkelbach
  204.  
  205. {
  206.    double pivot = M(p,q);
  207.    double pivot2;
  208.    int spalten = n+kl+2*gr+gl;
  209.    int zeilen = kl+gr+gl;
  210.  
  211.    for (int s=0; s<=spalten; s++)
  212.       M(p,s)= M(p,s)/pivot;
  213.    for (int z=0; z<p; z++)
  214.    {
  215.       pivot2 = M(z,q);
  216.       for (int s=0; s<=spalten; s++)
  217.      M(z,s) = M(z,s)-M(p,s)*pivot2;
  218.    }
  219.    for (z=p+1; z<=zeilen+1; z++)
  220.    {
  221.       pivot2 = M(z,q);
  222.       for (int s=0; s<=spalten; s++)
  223.      M(z,s) = M(z,s)-M(p,s)*pivot2;
  224.    }
  225. }
  226.  
  227.  
  228. static void NB_NNB_Update (int *&B, int *&NB, int p, int q, int l)
  229.  
  230. // Nach jedem Simplex-Schritt werden die Mengen der Basis- ( B ) und
  231. // Nichtbasisvariablen ( NB ) neu berechnet
  232.  
  233. // p und q bezeichnen die Pivotzeile bzw die Pivotspalte
  234.  
  235. // l ist die Groesse der Menge der Nichtbasisvariablen (diese aendert
  236. // sich im Laufe des Verfahrens)
  237.  
  238. {
  239.    int h1, h2;
  240.  
  241.    for (int x=0; x<l; x++)
  242.       if (NB[x] == q)
  243.      h1 = x;
  244.    h2 = B[p-1];
  245.    B [p-1] = q;
  246.    NB [h1] = h2;
  247. }
  248.  
  249.  
  250. static void NNB_Update (int *&NB, int n, int kl, int gr, int gl)
  251.  
  252. // Veringerung der Menge der Nichtbasisvariablen um die k’nstlichen Variablen
  253.  
  254. {
  255.    int *nnb = new int[n-gl];
  256.    int m = 0;
  257.  
  258.    for (int l=0; l<n+gr; l++)
  259.       if ( NB[l] <= n+kl+gr )
  260.       {
  261.      nnb[m] = NB[l];
  262.      m++;
  263.       }
  264.    delete NB;
  265.    NB = nnb;
  266. }
  267.  
  268.  
  269. static int nicht_optimal (matrix &M, int n, int kl, int gr)
  270.  
  271. // returniert 1, wenn das Simplextableau nicht optimal ist, sonst 0
  272.  
  273. {
  274.    double eps = 0.00001;    // das Intervall [-eps..eps] entspricht NULL
  275.  
  276.    int not_opt = 0;
  277.    for (int i=1; i<=n+gr+kl; i++)
  278.       if ( M(0,i) < -eps )
  279.      not_opt = 1;
  280.    return not_opt;
  281. }
  282.  
  283.  
  284. static void Eliminiere_kuenstl_Var (matrix M, int *&B, int *&NB, int &error,
  285.                  int m, int n, int kl, int gr, int gl)
  286.  
  287. // die kuenstlichen Variablen, die noch Basisvariablen sind, werden zu
  288. // Nichtbasisvariablen "pivotiert"
  289.  
  290. {
  291.    int q;
  292.  
  293.    int l=0;
  294.    while ( (l<m) && nicht_optimal(M,n,kl,gr) )
  295.    {
  296.       if (B[l] > n+kl+gr)
  297.       {
  298.      q = D_PivotSpalte (M,NB,l+1,n,kl,gr);
  299.          if ( (q != 0) && ( error == 0 ) )
  300.      {
  301.         Basiswechsel (M,l+1,q,n,kl,gr,gl);
  302.         NB_NNB_Update (B,NB,l+1,q,n+gr);
  303.      }
  304.      else
  305.         error = 1;
  306.       }
  307.       l++;
  308.    }
  309.    if ( (error==0) && nicht_optimal(M,n,kl,gr) )
  310.       NNB_Update (NB,n,kl,gr,gl);
  311. }
  312.  
  313.  
  314. static vector Basisloesung (matrix M, int *B, int m, int n)
  315.  
  316. // returniert eine optimale Basisloesung
  317.  
  318. {
  319.    vector X(n);
  320.  
  321.    for (int l=0; l<m; l++)
  322.       if ( B[l] <= n )
  323.      X[B[l]-1] = M(l+1,0);
  324.  
  325.    return X;
  326. }
  327.  
  328.  
  329. static vector Extremalstrahl (matrix M, int *&B, int *&MF, int l, int m, int n)
  330.  
  331. // returniert die Steigung des Extremalstrahls
  332.  
  333. {
  334.    vector s(n);
  335.  
  336.    for (int j=0; j<m; j++)
  337.       if ( B[j] <= n )
  338.     s[B[j]-1] = -M(j+1,MF[l]);
  339.  
  340.    if ( MF[l] <= n )
  341.       s[MF[l]-1]=1;
  342.  
  343.    return s;
  344. }
  345.  
  346.  
  347. static int ZERO (vector v,int n)
  348.  
  349. // returniert 1, falls v gleich dem Nullvektor ist, sonst 0
  350.  
  351. {
  352.    double eps = 0.00001;    // das Intervall [-eps..eps] entspricht NULL
  353.  
  354.    int zero = 1;
  355.  
  356.    for (int i=0; i<n; i++)
  357.       if ( (v[i] < -eps) || (v[i] > eps) )
  358.          zero = 0;
  359.  
  360.    return zero;
  361. }
  362.  
  363.  
  364. static void Init_Matrix (matrix &A, vector x, int n)
  365.  
  366. // initialisiert die (1xn)-Matrix mit dem Vektor x
  367.  
  368. {
  369.    for (int i=0; i<n; i++)
  370.       A(0,i) = x[i];
  371. }
  372.  
  373.  
  374. static void Enlarge_Matrix (matrix &A, vector v, int n)
  375.  
  376. // vergroessert die Matrix A um den Zeilenvektor v
  377.  
  378. {
  379.    int dim1 = A.dim1();
  380.    matrix B(dim1+1,A.dim2());
  381.  
  382.    InitMatrix (B,A,dim1,A.dim2());
  383.  
  384.    for (int i=0; i<n; i++)
  385.       B(dim1,i) = v[i];
  386.  
  387.    A = B;
  388. }
  389.  
  390.  
  391. static void Test_auf_Extremalstrahl (matrix &M,int *&B,int *&NB,list<matrix>& L,
  392.                   int *&MF, int *&PZ, int i, vector x, int m, 
  393.                               int n, int kl, int gr)
  394.  
  395. // Berechnung und Ausgabe eines optimalen Extremalstrahls
  396. // Aufbau der Liste L der optimalen Loesungen
  397.  
  398. {
  399.    vector s(n);
  400.    matrix A (1,n);
  401.  
  402.    Init_Matrix (A,x,n);
  403.  
  404.    for (int l=0; l<i; l++)
  405.       if ( NB[l] <= n+gr+kl )             // Test ob im optimalen Tableau ein
  406.      if ( M(0,NB[l]) == 0 )        // Zielfunktionskoeffient einer Nicht-
  407.         MF[l] = NB[l];                // basisvariable = 0 ist
  408.      else
  409.         MF[l] = 0;
  410.       else
  411.          MF[l] = 0;
  412.  
  413.    for ( l=0; l<i; l++)
  414.    {
  415.       if ( MF[l] > 0 )
  416.       {
  417.      PZ[l] = PivotZeile (M,MF[l],m);
  418.      if ( PZ[l] == 0 )
  419.      {
  420.         s = Extremalstrahl (M,B,MF,l,m,n);
  421.         if ( !ZERO(s,n) )
  422.            Enlarge_Matrix (A,s,n);
  423.      }
  424.       }
  425.    }
  426.  
  427.    L.append (A);
  428. }
  429.  
  430.  
  431. static
  432. void Test_auf_Mehrfachloesungen(matrix &M,int *&B,int *&NB,list<matrix> &L,
  433.                 int x, vector v,int zeilen, int spalten,
  434.                 int m, int n, int kl, int gr, int gl)
  435.  
  436. // Berechnung von eventuell existierenden weiteren optimalen Basisloesungen
  437. // x ist die Groesse der Menge der Nichtbasisvariablen
  438.  
  439. {
  440.                     // Hilfsmatrix zur Berechnung weiterer
  441.    matrix A (m+2,n+kl+2*gr+gl+1);   // optimaler Simplextableaus
  442.  
  443.    int *MF = new int[x];              // fuer die Indizes der Spalten in
  444.                       // denen die 0.te Zeile =0 ist
  445.    int *PZ = new int[x];              // die zugehoerigen Pivotzeilen
  446.  
  447.    int *H1 = new int[x];              // Hilfsarrays
  448.    int *H2 = new int[x];
  449.  
  450.    int *b = new int [m];              // Hilfsarrays fuer B
  451.    int *nb = new int [x];             // und NB
  452.  
  453.  
  454.    Test_auf_Extremalstrahl (M,B,NB,L,MF,PZ,x,v,m,n,kl,gr);
  455.  
  456.    for (int l=0; l<x; l++)
  457.    {
  458.       if ( MF[l] > 0 )
  459.      if ( PZ[l] > 0 )
  460.      {
  461.         InitMatrix (A,M,zeilen,spalten);
  462.         InitIntArray (b,B,m);
  463.         InitIntArray (nb,NB,x);
  464.         Basiswechsel (A,PZ[l],MF[l],n,kl,gr,gl);
  465.         NB_NNB_Update (b,nb,PZ[l],MF[l],x);
  466.         v = Basisloesung (A,b,m,n);
  467.         Test_auf_Extremalstrahl (A,b,nb,L,H1,H2,x,v,m,n,kl,gr);
  468.                          // H1, H2 sind Hilfsarrays
  469.      }
  470.    }
  471.    delete MF; delete PZ; delete H1;
  472.    delete H2; delete b; delete nb;
  473. }
  474.  
  475.  
  476. static
  477. void Run (matrix &M, int *&B, int *&NB, list<matrix> &L, int zeilen, 
  478.           int spalten, int m, int n, int kl, int gr, int gl)
  479.  
  480. // Hauptprozedur
  481.  
  482. {
  483.    double eps = 0.00001;    // das Intervall [-eps..eps] entspricht NULL
  484.  
  485.    int p, q;
  486.    int error=0;
  487.    vector x;
  488.  
  489.    q = PivotSpalte (M,NB,m+1,n+gr,m);
  490.    while (q != 0)
  491.    {
  492.       p = PivotZeile (M,q,m);
  493.       if (p != 0)
  494.       {
  495.      Basiswechsel (M,p,q,n,kl,gr,gl);
  496.      NB_NNB_Update (B,NB,p,q,n+gr);
  497.       }
  498.       q = PivotSpalte (M,NB,m+1,n+gr,m);
  499.    }
  500.  
  501.    if ( ( M(m+1,0) > -eps ) && ( M(m+1,0) < eps ) )
  502.    {
  503.  
  504.       Eliminiere_kuenstl_Var (M,B,NB,error,m,n,kl,gr,gl);
  505.       if ( nicht_optimal (M,n,kl,gr) )
  506.       {
  507.  
  508. // falls error = 1 so konnte ein notwendiger Dualsimplexschritt nicht
  509. // durchgefuehrt werden
  510.  
  511.      if ( error == 0 )
  512.      {
  513.         q = PivotSpalte (M,NB,0,n-gl,m);
  514.         while (q != 0)
  515.         {
  516.            p = PivotZeile (M,q,m);
  517.            if (p != 0)
  518.            {
  519.           Basiswechsel (M,p,q,n,kl,gr,gl);
  520.           NB_NNB_Update (B,NB,p,q,n-gl);
  521.            }
  522.            q = PivotSpalte (M,NB,0,n-gl,m);
  523.         }
  524.         x = Basisloesung(M,B,m,n);
  525.         Test_auf_Mehrfachloesungen(M,B,NB,L,n-gl,x,zeilen,
  526.                        spalten,m,n,kl,gr,gl);
  527.      }
  528.       }
  529.       else                              // das Tableau war schon optimal
  530.       {
  531.       x = Basisloesung(M,B,m,n);
  532.       Test_auf_Mehrfachloesungen (M,B,NB,L,n+gr,x,zeilen,
  533.                       spalten,m,n,kl,gr,gl);
  534.       }
  535.    }
  536. }
  537.  
  538.  
  539. list<matrix> SIMPLEX(matrix A, int i, int j, int k, vector b, vector c)
  540. {
  541.    int *B; int *NB;
  542.  
  543.    list<matrix> L;
  544.  
  545.    int kl =i,  gr=j, gl=k;
  546.    int n = A.dim2(),m = A.dim1();        // setzen der globalen Variablen
  547.    int zeilen = m+2, spalten = n+m+gr+1;
  548.  
  549.    matrix M(zeilen,spalten);
  550.    B  = new int[m];
  551.    NB = new int[n+gr];
  552.  
  553.    Init_Tableau(A,M,c,b,i,j,k,B,NB,zeilen,spalten,n);
  554.  
  555.    Run (M,B,NB,L,zeilen,spalten,m,n,kl,gr,gl);
  556.  
  557.    delete B; delete NB;
  558.  
  559.    return L;
  560. }
  561.  
  562.